#line 1 "parser.rl"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include "parser.h"

/* define default callbacks */
static void 
esi_parser_default_start_cb( const void *data,
                             const char *name_start,
                             size_t name_length,
                             ESIAttribute *attributes,
                             void *user_data )
{
}
static void 
esi_parser_default_end_cb( const void *data,
                           const char *name_start,
                           size_t name_length,
                           void *user_data )
{
}
static void 
esi_parser_default_output_cp(const void *data,
                             size_t length,
                             void *user_data)
{
}
#ifdef DEBUG
static void debug_string( const char *msg, const char *str, size_t len )
{
  char *pstr = esi_strndup( str, len );
  printf( "%s :'%s'\n", msg, pstr );
  free( pstr );
}
#endif

static void esi_parser_echo_char( ESIParser *parser, char ch )
{
  parser->output_handler( (void*)&ch, 1, parser->user_data );
}

static void esi_parser_echo_buffer( ESIParser *parser )
{
//  debug_string( "echobuffer", parser->echobuffer, parser->echobuffer_index+1 );
  parser->output_handler( parser->echobuffer, parser->echobuffer_index+1, parser->user_data );
}

static void esi_parser_echobuffer_clear( ESIParser *parser )
{
  parser->echobuffer_index = -1;
}

static void esi_parser_concat_to_echobuffer( ESIParser *parser, char ch )
{
  parser->echobuffer_index++;

  if( parser->echobuffer_allocated <= parser->echobuffer_index ){
    // double the echobuffer size
    parser->echobuffer_allocated *= 2;
    parser->echobuffer = (char*)realloc( parser->echobuffer, parser->echobuffer_allocated );
  }
  parser->echobuffer[parser->echobuffer_index] = ch;
//  debug_string( "echo buffer", parser->echobuffer, parser->echobuffer_index+1 );
}

static void ltrim_pointer( const char **ptr, const char *bounds, size_t *len )
{
  // remove any spaces or = at the before the value
  while( isspace( **ptr ) ||
         **ptr == '=' ||
         **ptr == '"' ||
         **ptr == '\'' &&
         *len > 0 &&
         (*ptr != bounds) ){
    (*ptr)++;
    (*len)--;
  }
}

#line 182 "parser.rl"



#line 88 "parser.c"
static const char _esi_actions[] = {
	0, 1, 9, 2, 9, 0, 2, 9, 
	1, 2, 9, 2, 2, 9, 3, 2, 
	9, 4, 2, 9, 5, 2, 9, 6, 
	2, 9, 7, 2, 9, 8, 3, 9, 
	0, 1, 3, 9, 3, 1, 4, 9, 
	0, 3, 1, 4, 9, 3, 6, 1
	
};

static const short _esi_key_offsets[] = {
	0, 1, 4, 6, 8, 10, 12, 15, 
	19, 21, 23, 25, 28, 36, 48, 59, 
	69, 75, 85, 94, 106, 117, 119, 130, 
	140, 150, 160, 170, 180, 191, 201, 211, 
	221, 231, 246, 256, 265, 277, 288, 298, 
	304, 314, 325, 335, 345, 355, 365, 375, 
	386, 396, 406, 416, 426, 441, 451, 453, 
	455, 456, 457, 466, 475
};

static const char _esi_trans_keys[] = {
	60, 47, 60, 101, 60, 101, 60, 115, 
	60, 105, 58, 60, 60, 97, 122, 60, 
	62, 97, 122, 60, 115, 60, 105, 58, 
	60, 60, 97, 122, 32, 47, 60, 62, 
	9, 13, 97, 122, 32, 45, 47, 60, 
	62, 95, 9, 13, 65, 90, 97, 122, 
	32, 45, 47, 60, 95, 9, 13, 65, 
	90, 97, 122, 45, 60, 61, 95, 48, 
	57, 65, 90, 97, 122, 32, 34, 39, 
	60, 9, 13, 33, 60, 95, 125, 35, 
	38, 40, 90, 97, 123, 34, 39, 60, 
	95, 125, 33, 90, 97, 123, 32, 45, 
	47, 60, 62, 95, 9, 13, 65, 90, 
	97, 122, 32, 45, 47, 60, 95, 9, 
	13, 65, 90, 97, 122, 60, 62, 34, 
	39, 47, 60, 95, 101, 125, 33, 90, 
	97, 123, 34, 39, 60, 95, 101, 125, 
	33, 90, 97, 123, 34, 39, 60, 95, 
	115, 125, 33, 90, 97, 123, 34, 39, 
	60, 95, 105, 125, 33, 90, 97, 123, 
	34, 39, 58, 60, 95, 125, 33, 90, 
	97, 123, 34, 39, 60, 95, 123, 125, 
	33, 90, 97, 122, 34, 39, 60, 62, 
	95, 123, 125, 33, 90, 97, 122, 34, 
	39, 60, 95, 115, 125, 33, 90, 97, 
	123, 34, 39, 60, 95, 105, 125, 33, 
	90, 97, 123, 34, 39, 58, 60, 95, 
	125, 33, 90, 97, 123, 34, 39, 60, 
	95, 123, 125, 33, 90, 97, 122, 32, 
	34, 39, 47, 60, 62, 95, 123, 125, 
	9, 13, 33, 90, 97, 122, 34, 39, 
	60, 62, 95, 125, 33, 90, 97, 123, 
	34, 39, 60, 95, 125, 33, 90, 97, 
	123, 32, 45, 47, 60, 62, 95, 9, 
	13, 65, 90, 97, 122, 32, 45, 47, 
	60, 95, 9, 13, 65, 90, 97, 122, 
	45, 60, 61, 95, 48, 57, 65, 90, 
	97, 122, 32, 34, 39, 60, 9, 13, 
	33, 60, 95, 125, 35, 38, 40, 90, 
	97, 123, 34, 39, 47, 60, 95, 101, 
	125, 33, 90, 97, 123, 34, 39, 60, 
	95, 101, 125, 33, 90, 97, 123, 34, 
	39, 60, 95, 115, 125, 33, 90, 97, 
	123, 34, 39, 60, 95, 105, 125, 33, 
	90, 97, 123, 34, 39, 58, 60, 95, 
	125, 33, 90, 97, 123, 34, 39, 60, 
	95, 123, 125, 33, 90, 97, 122, 34, 
	39, 60, 62, 95, 123, 125, 33, 90, 
	97, 122, 34, 39, 60, 95, 115, 125, 
	33, 90, 97, 123, 34, 39, 60, 95, 
	105, 125, 33, 90, 97, 123, 34, 39, 
	58, 60, 95, 125, 33, 90, 97, 123, 
	34, 39, 60, 95, 123, 125, 33, 90, 
	97, 122, 32, 34, 39, 47, 60, 62, 
	95, 123, 125, 9, 13, 33, 90, 97, 
	122, 34, 39, 60, 62, 95, 125, 33, 
	90, 97, 123, 60, 62, 60, 62, 60, 
	60, 34, 39, 60, 95, 125, 33, 90, 
	97, 123, 34, 39, 60, 95, 125, 33, 
	90, 97, 123, 60, 0
};

static const char _esi_single_lengths[] = {
	1, 3, 2, 2, 2, 2, 1, 2, 
	2, 2, 2, 1, 4, 6, 5, 4, 
	4, 4, 5, 6, 5, 2, 7, 6, 
	6, 6, 6, 6, 7, 6, 6, 6, 
	6, 9, 6, 5, 6, 5, 4, 4, 
	4, 7, 6, 6, 6, 6, 6, 7, 
	6, 6, 6, 6, 9, 6, 2, 2, 
	1, 1, 5, 5, 1
};

static const char _esi_range_lengths[] = {
	0, 0, 0, 0, 0, 0, 1, 1, 
	0, 0, 0, 1, 2, 3, 3, 3, 
	1, 3, 2, 3, 3, 0, 2, 2, 
	2, 2, 2, 2, 2, 2, 2, 2, 
	2, 3, 2, 2, 3, 3, 3, 1, 
	3, 2, 2, 2, 2, 2, 2, 2, 
	2, 2, 2, 2, 3, 2, 0, 0, 
	0, 0, 2, 2, 0
};

static const short _esi_index_offsets[] = {
	0, 2, 6, 9, 12, 15, 18, 21, 
	25, 28, 31, 34, 37, 44, 54, 63, 
	71, 77, 85, 93, 103, 112, 115, 125, 
	134, 143, 152, 161, 170, 180, 189, 198, 
	207, 216, 229, 238, 246, 256, 265, 273, 
	279, 287, 297, 306, 315, 324, 333, 342, 
	352, 361, 370, 379, 388, 401, 410, 413, 
	416, 418, 420, 428, 436
};

static const char _esi_indicies[] = {
	1, 0, 2, 1, 3, 0, 1, 4, 
	0, 1, 5, 0, 1, 6, 0, 7, 
	1, 0, 1, 8, 0, 1, 9, 8, 
	0, 1, 10, 0, 1, 11, 0, 12, 
	1, 0, 1, 13, 0, 14, 15, 1, 
	16, 14, 13, 0, 17, 18, 19, 1, 
	20, 18, 17, 18, 18, 0, 17, 18, 
	19, 1, 18, 17, 18, 18, 0, 18, 
	1, 21, 18, 18, 18, 18, 0, 22, 
	23, 23, 1, 22, 0, 24, 25, 24, 
	24, 24, 24, 24, 0, 26, 26, 25, 
	24, 24, 24, 24, 0, 27, 18, 28, 
	1, 20, 18, 27, 18, 18, 0, 27, 
	18, 28, 1, 18, 27, 18, 18, 0, 
	1, 29, 0, 26, 26, 30, 25, 24, 
	31, 24, 24, 24, 0, 26, 26, 25, 
	24, 32, 24, 24, 24, 0, 26, 26, 
	25, 24, 33, 24, 24, 24, 0, 26, 
	26, 25, 24, 34, 24, 24, 24, 0, 
	26, 26, 35, 25, 24, 24, 24, 24, 
	0, 26, 26, 25, 24, 24, 24, 24, 
	36, 0, 26, 26, 25, 37, 24, 24, 
	24, 24, 36, 0, 26, 26, 25, 24, 
	38, 24, 24, 24, 0, 26, 26, 25, 
	24, 39, 24, 24, 24, 0, 26, 26, 
	40, 25, 24, 24, 24, 24, 0, 26, 
	26, 25, 24, 24, 24, 24, 41, 0, 
	14, 26, 26, 42, 25, 43, 24, 24, 
	24, 14, 24, 41, 0, 26, 26, 25, 
	44, 24, 24, 24, 24, 0, 46, 46, 
	47, 45, 45, 45, 45, 0, 48, 49, 
	28, 1, 20, 49, 48, 49, 49, 0, 
	48, 49, 28, 1, 49, 48, 49, 49, 
	0, 49, 1, 50, 49, 49, 49, 49, 
	0, 51, 52, 52, 1, 51, 0, 45, 
	47, 45, 45, 45, 45, 45, 0, 46, 
	46, 53, 47, 45, 54, 45, 45, 45, 
	0, 46, 46, 47, 45, 55, 45, 45, 
	45, 0, 46, 46, 47, 45, 56, 45, 
	45, 45, 0, 46, 46, 47, 45, 57, 
	45, 45, 45, 0, 46, 46, 58, 47, 
	45, 45, 45, 45, 0, 46, 46, 47, 
	45, 45, 45, 45, 59, 0, 46, 46, 
	47, 60, 45, 45, 45, 45, 59, 0, 
	46, 46, 47, 45, 61, 45, 45, 45, 
	0, 46, 46, 47, 45, 62, 45, 45, 
	45, 0, 46, 46, 63, 47, 45, 45, 
	45, 45, 0, 46, 46, 47, 45, 45, 
	45, 45, 64, 0, 14, 46, 46, 65, 
	47, 66, 45, 45, 45, 14, 45, 64, 
	0, 46, 46, 47, 67, 45, 45, 45, 
	45, 0, 1, 68, 0, 1, 69, 0, 
	1, 0, 71, 70, 74, 74, 75, 73, 
	73, 73, 73, 72, 74, 74, 75, 73, 
	73, 73, 73, 72, 76, 72, 0
};

static const char _esi_trans_targs_wi[] = {
	0, 1, 2, 8, 3, 4, 5, 6, 
	7, 0, 9, 10, 11, 12, 13, 55, 
	0, 14, 15, 54, 57, 16, 16, 17, 
	18, 22, 19, 20, 21, 57, 23, 29, 
	24, 25, 26, 27, 28, 18, 30, 31, 
	32, 33, 34, 18, 58, 35, 36, 41, 
	37, 38, 39, 39, 40, 42, 48, 43, 
	44, 45, 46, 47, 35, 49, 50, 51, 
	52, 53, 35, 59, 60, 60, 0, 1, 
	0, 35, 36, 41, 1
};

static const char _esi_trans_actions_wi[] = {
	1, 3, 1, 1, 1, 1, 1, 1, 
	1, 27, 1, 1, 1, 1, 9, 9, 
	24, 1, 1, 9, 15, 18, 1, 1, 
	1, 3, 21, 1, 1, 12, 1, 1, 
	1, 1, 1, 1, 1, 27, 1, 1, 
	1, 1, 9, 24, 1, 1, 21, 3, 
	1, 1, 18, 1, 1, 1, 1, 1, 
	1, 1, 1, 1, 27, 1, 1, 1, 
	1, 9, 24, 1, 12, 1, 6, 30, 
	34, 34, 43, 38, 38
};

static const int esi_start = 56;
static const int esi_first_final = 56;
static const int esi_error = -1;

static const int esi_en_main = 56;

#line 185 "parser.rl"

char *esi_strndup( const char *str, size_t len )
{
  char *s = (char*)malloc(sizeof(char)*(len+1));
  memcpy( s, str, len );
  s[len] = '\0';
  return s;
}

ESIAttribute *esi_attribute_new( const char *name, size_t name_length, const char *value, size_t value_length )
{
  ESIAttribute *attr = (ESIAttribute*)malloc(sizeof(ESIAttribute));
  attr->name = esi_strndup(name, name_length);
  attr->value = esi_strndup(value, value_length);
  attr->next = NULL;
  return attr;
}

void esi_attribute_free( ESIAttribute *attribute )
{
  ESIAttribute *ptr;
  while( attribute ){
    free( attribute->name );
    free( attribute->value );
    ptr = attribute->next;
    free( attribute );
    attribute = ptr;
  }
}

ESIParser *esi_parser_new()
{
  ESIParser *parser = (ESIParser*)malloc(sizeof(ESIParser));
  parser->cs = esi_start;
  parser->mark = NULL;
  parser->overflow_data_size = 0;
  parser->overflow_data = NULL;

  /* allocate 1024 bytes for the echobuffer */
  parser->echobuffer_allocated = 1024;
  parser->echobuffer_index = -1;
  parser->echobuffer = (char*)malloc(sizeof(char)*parser->echobuffer_allocated);

  parser->attributes = NULL;
  parser->last = NULL;

  parser->start_tag_handler = esi_parser_default_start_cb;
  parser->end_tag_handler = esi_parser_default_end_cb;
  parser->output_handler = esi_parser_default_output_cp;

  return parser;
}
void esi_parser_free( ESIParser *parser )
{
  if( parser->overflow_data ){ free( parser->overflow_data ); }

  free( parser->echobuffer );
  esi_attribute_free( parser->attributes );

  free( parser );
}

void esi_parser_output_handler( ESIParser *parser, output_cb output_handler )
{
  parser->output_handler = output_handler;
}

int esi_parser_init( ESIParser *parser )
{
  int cs;
  
#line 368 "parser.c"
	{
	cs = esi_start;
	}
#line 256 "parser.rl"
  parser->prev_state = parser->cs = cs;
  return 0;
}

static int compute_offset( const char *mark, const char *data )
{
  if( mark ){
    return mark - data;
  }
  return -1;
}

int esi_parser_execute( ESIParser *parser, const char *data, size_t length )
{
  int cs = parser->cs;
  const char *p = data;
  const char *pe = data + length;

  if( length == 0 ){ return cs; }

  if( parser->overflow_data && parser->overflow_data_size > 0 ){

    // recompute mark, tag_text, attr_key, and attr_value since they all exist within overflow_data
    int mark_offset = compute_offset( parser->mark, parser->overflow_data );
    int tag_text_offset = compute_offset( parser->tag_text, parser->overflow_data );
    int attr_key_offset = compute_offset( parser->attr_key, parser->overflow_data );
    int attr_value_offset = compute_offset( parser->attr_value, parser->overflow_data );

//    debug_string("grow overflow buffer", parser->overflow_data, parser->overflow_data_size );

    parser->overflow_data = (char*)realloc( parser->overflow_data, sizeof(char)*(parser->overflow_data_size+length) );
    memcpy( parser->overflow_data+parser->overflow_data_size, data, length );

    p = parser->overflow_data + parser->overflow_data_size;
    
    // in our new memory space mark will now be
    parser->mark = ( mark_offset > 0 ) ? parser->overflow_data + mark_offset : NULL;
    parser->tag_text = ( tag_text_offset > 0 ) ? parser->overflow_data + tag_text_offset : NULL;
    parser->attr_key = ( attr_key_offset > 0 ) ? parser->overflow_data + attr_key_offset : NULL;
    parser->attr_value = ( attr_value_offset > 0 ) ? parser->overflow_data + attr_value_offset : NULL;
 
    data = parser->overflow_data;
    parser->overflow_data_size = length = length + parser->overflow_data_size;
    pe = data + length;

//    debug_string( "overflow", parser->overflow_data, parser->overflow_data_size );
  }

  if( !parser->mark ){
    parser->mark = p;
  }

//  printf( "cs: %d, ", cs );
//  debug_string( "data", data, length );

  
#line 429 "parser.c"
	{
	int _klen;
	unsigned int _trans;
	const char *_acts;
	unsigned int _nacts;
	const char *_keys;

	if ( p == pe )
		goto _out;
_resume:
	_keys = _esi_trans_keys + _esi_key_offsets[cs];
	_trans = _esi_index_offsets[cs];

	_klen = _esi_single_lengths[cs];
	if ( _klen > 0 ) {
		const char *_lower = _keys;
		const char *_mid;
		const char *_upper = _keys + _klen - 1;
		while (1) {
			if ( _upper < _lower )
				break;

			_mid = _lower + ((_upper-_lower) >> 1);
			if ( (*p) < *_mid )
				_upper = _mid - 1;
			else if ( (*p) > *_mid )
				_lower = _mid + 1;
			else {
				_trans += (_mid - _keys);
				goto _match;
			}
		}
		_keys += _klen;
		_trans += _klen;
	}

	_klen = _esi_range_lengths[cs];
	if ( _klen > 0 ) {
		const char *_lower = _keys;
		const char *_mid;
		const char *_upper = _keys + (_klen<<1) - 2;
		while (1) {
			if ( _upper < _lower )
				break;

			_mid = _lower + (((_upper-_lower) >> 1) & ~1);
			if ( (*p) < _mid[0] )
				_upper = _mid - 2;
			else if ( (*p) > _mid[1] )
				_lower = _mid + 2;
			else {
				_trans += ((_mid - _keys)>>1);
				goto _match;
			}
		}
		_trans += _klen;
	}

_match:
	_trans = _esi_indicies[_trans];
	cs = _esi_trans_targs_wi[_trans];

	if ( _esi_trans_actions_wi[_trans] == 0 )
		goto _again;

	_acts = _esi_actions + _esi_trans_actions_wi[_trans];
	_nacts = (unsigned int) *_acts++;
	while ( _nacts-- > 0 )
	{
		switch ( *_acts++ )
		{
	case 0:
#line 85 "parser.rl"
	{
    parser->mark = p;
//    printf( "begin\n" );
  }
	break;
	case 1:
#line 89 "parser.rl"
	{
//    printf( "finish\n" );
  }
	break;
	case 2:
#line 94 "parser.rl"
	{
    parser->tag_text = parser->mark+1;
    parser->tag_text_length = p - (parser->mark+1);
//    debug_string( "have esi start", parser->tag_text, parser->tag_text_length );
    parser->mark = p;
  }
	break;
	case 3:
#line 101 "parser.rl"
	{
//    debug_string( "parsed esi tag", parser->tag_text, parser->tag_text_length );
    parser->start_tag_handler( data, parser->tag_text, parser->tag_text_length, parser->attributes, parser->user_data );
    parser->end_tag_handler( data, parser->tag_text, parser->tag_text_length, parser->user_data );
    parser->tag_text = NULL;
    parser->tag_text_length = 0;
  }
	break;
	case 4:
#line 109 "parser.rl"
	{
//    debug_string( "parsed esi tag", parser->tag_text, parser->tag_text_length );
    parser->start_tag_handler( data, parser->tag_text, parser->tag_text_length, parser->attributes, parser->user_data );
    parser->tag_text = NULL;
    parser->tag_text_length = 0;
  }
	break;
	case 5:
#line 116 "parser.rl"
	{
    parser->attr_key = parser->mark;
    parser->attr_key_length = p - parser->mark;
    parser->mark = p;
    ltrim_pointer( &(parser->attr_key), p, &(parser->attr_key_length) );
//    debug_string( "\tattribute key", parser->attr_key, parser->attr_key_length );
  }
	break;
	case 6:
#line 124 "parser.rl"
	{
    ESIAttribute *attr;
    parser->attr_value = parser->mark;
    parser->attr_value_length = p - parser->mark;
    parser->mark = p;

    ltrim_pointer( &(parser->attr_value), p, &(parser->attr_value_length) );

    // allocate a new attribute
    attr = esi_attribute_new( parser->attr_key, parser->attr_key_length, 
                              parser->attr_value, parser->attr_value_length );
    if( parser->attributes ){
      parser->last->next = attr;
      parser->last = attr;
    }
    else{
      parser->last = parser->attributes = attr;
    }
//    debug_string( "\tattribute value", parser->attr_value, parser->attr_value_length );
  }
	break;
	case 7:
#line 145 "parser.rl"
	{
    parser->tag_text = parser->mark;
    parser->tag_text_length = p - parser->mark;
    parser->mark = p;
    parser->start_tag_handler( data, parser->tag_text, parser->tag_text_length, NULL, parser->user_data );
  }
	break;
	case 8:
#line 152 "parser.rl"
	{
    parser->tag_text = parser->mark+2;
    parser->tag_text_length = p - (parser->mark+2);
    parser->mark = p;
    parser->end_tag_handler( data, parser->tag_text, parser->tag_text_length, parser->user_data );
  }
	break;
	case 9:
#line 159 "parser.rl"
	{
    switch( cs ){
    case 0:
      if( parser->prev_state != 12 && parser->prev_state != 7 ){
        if( parser->echobuffer && (parser->prev_state != (esi_en_main +1)) && parser->prev_state != 60 ){
          // stream echobuffer
          esi_parser_echo_buffer( parser );
        }
//    printf( "[%d: %c]", cs, *p );
        // stream the current character
        esi_parser_echo_char( parser, *p );
      }
      // clear the echobuffer
      esi_parser_echobuffer_clear( parser );
      break;
    default:
      // append characters to echobuffer
      esi_parser_concat_to_echobuffer( parser, *p );
    }
    parser->prev_state = cs;
  }
	break;
#line 617 "parser.c"
		}
	}

_again:
	if ( ++p != pe )
		goto _resume;
	_out: {}
	}
#line 312 "parser.rl"

  parser->cs = cs;

  if( cs != esi_start && cs != 0 ){

    if( !parser->overflow_data ){
      // recompute mark, tag_text, attr_key, and attr_value since they all exist within overflow_data
      int mark_offset = compute_offset( parser->mark, data );
      int tag_text_offset = compute_offset( parser->tag_text, data );
      int attr_key_offset = compute_offset( parser->attr_key, data );
      int attr_value_offset = compute_offset( parser->attr_value, data );

      parser->overflow_data = (char*)malloc( sizeof( char ) * length );
      memcpy( parser->overflow_data, data, length );
      parser->overflow_data_size = length;

      // in our new memory space mark will now be
      parser->mark = ( mark_offset > 0 ) ? parser->overflow_data + mark_offset : NULL;
      parser->tag_text = ( tag_text_offset > 0 ) ? parser->overflow_data + tag_text_offset : NULL;
      parser->attr_key = ( attr_key_offset > 0 ) ? parser->overflow_data + attr_key_offset : NULL;
      parser->attr_value = ( attr_value_offset > 0 ) ? parser->overflow_data + attr_value_offset : NULL;
    }

  }else if( parser->overflow_data ){
    free( parser->overflow_data );
    parser->overflow_data = NULL;
    parser->overflow_data_size = 0;
  }

  return cs;
}
int esi_parser_finish( ESIParser *parser )
{
  
#line 661 "parser.c"
#line 346 "parser.rl"
  return 0;
}

void esi_parser_start_tag_handler( ESIParser *parser, start_tag_cb callback )
{
  parser->start_tag_handler = callback;
}

void esi_parser_end_tag_handler( ESIParser *parser, end_tag_cb callback )
{
  parser->end_tag_handler = callback;
}
